﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using EnvDTE;
using System.IO;
using EnvDTE80;
using System.Collections;

namespace SPVisualDev.VSAddin.Dialogs
{
    internal partial class DialogCodeFileSelector : Form
    {
        private Project m_startup_project;
        private string m_default_namespace;
        private ProjectItem m_startup_code_folder_created;

        public DialogCodeFileSelector(Project project, string DefaultNamespace)
        {
            InitializeComponent();

            m_startup_project = project;
            m_default_namespace = DefaultNamespace;

            this.Load += new EventHandler(DialogCodeFileSelector_Load);
            this.FormClosing += new FormClosingEventHandler(DialogCodeFileSelector_FormClosing);

            this.rdoClasses.Checked = true;
            this.rdoClasses.CheckedChanged += new EventHandler(rdoClasses_CheckedChanged);
        }

        void DialogCodeFileSelector_FormClosing(object sender, FormClosingEventArgs e)
        {
            try
            {
                if (m_startup_code_folder_created != null)
                {
                    if (m_startup_code_folder_created.ProjectItems.Count == 0)
                    {
                        m_startup_code_folder_created.Delete();
                        m_startup_code_folder_created = null;
                    }
                }
            }
            catch (Exception ex)
            {
                DialogError.ShowError(ex);
            }
        }

        void rdoClasses_CheckedChanged(object sender, EventArgs e)
        {
            RefreshVisibleControls();
        }

        private void RefreshVisibleControls()
        {
            if (this.rdoClasses.Checked)
            {
                ShowClassExplorer();

                this.btnAddFeatureEventReceiver.Enabled = false;
                this.btnAddFromFile.Enabled = false;
                this.btnAddFromOtherTemplates.Enabled = false;
                this.btnAddItemEventRec.Enabled = false;
                this.btnAddListEventRec.Enabled = false;
                this.btnCreateFolder.Enabled = false;
                this.btnDelete.Enabled = false;
            }
            else
            {
                ShowProjectExplorer();

                this.btnAddFeatureEventReceiver.Enabled = true;
                this.btnAddFromFile.Enabled = true;
                this.btnAddFromOtherTemplates.Enabled = true;
                this.btnAddItemEventRec.Enabled = true;
                this.btnAddListEventRec.Enabled = true;
                this.btnCreateFolder.Enabled = true;
                this.btnDelete.Enabled = true;
            }
        }

        private void ShowClassExplorer()
        {
            this.ucClassExplorer1.BringToFront();
            this.ucClassExplorer1.Focus();
        }

        private void ShowProjectExplorer()
        {
            this.ProjectExplorer.BringToFront();
            this.ProjectExplorer.Focus();
        }

        private void DialogCodeFileSelector_Load(object sender, EventArgs e)
        {
            try
            {
                ProjectExplorer.Initialize(m_startup_project);
                ProjectExplorer.ShowFiles = !this.FolderView;
                ProjectExplorer.ShowFolders = true;

                if (this.FolderView)
                {
                    this.btnAddFeatureEventReceiver.Visible = false;
                    this.btnAddFromFile.Visible = false;
                    this.btnAddFromOtherTemplates.Visible = false;
                    this.btnAddItemEventRec.Visible = false;
                    this.btnAddListEventRec.Visible = false;
                }
                else
                {
                    if (!string.IsNullOrEmpty(this.StartupFolder))
                    {
                        if (this.StartupFolder.StartsWith("12\\TEMPLATE\\FEATURES", StringComparison.OrdinalIgnoreCase))
                        {
                            ProjectItem codeFolder = Common.GetProjectItem(m_startup_project, this.StartupFolder, "\\");
                            if (codeFolder == null)
                            {
                                m_startup_code_folder_created = Common.CreateProjectItemPath(m_startup_project, this.StartupFolder);
                            }
                        }
                        
                    }
                }

                //this.btnAddFeatureEventReceiver.Enabled = false;
                //this.btnAddFromFile.Enabled = false;
                //this.btnAddFromOtherTemplates.Enabled = false;
                //this.btnAddItemEventRec.Enabled = false;
                //this.btnAddListEventRec.Enabled = false;
                //this.btnCreateFolder.Enabled = false;
                //this.btnDelete.Enabled = false;

                RefreshVisibleControls();

                ucClassExplorer1.ShowOnlyProjectClasses = true;
                ucClassExplorer1.Initialize(m_startup_project);
                ucClassExplorer1.RenderRootNode();

                ProjectExplorer.RenderRootNode();
                ProjectExplorer.Refresh();

                ProjectExplorer.TreeView.HideSelection = false;

                if (ProjectExplorer.TreeView.TopNode != null)
                {
                    ProjectExplorer.TreeView.SelectedNode = ProjectExplorer.TreeView.TopNode;

                    if (!string.IsNullOrEmpty(StartupFolder))
                    {
                        TreeNode[] nodeColl = ProjectExplorer.TreeView.Nodes.Find(ProjectExplorer.TreeView.TopNode.Name + "\\" + StartupFolder, true);
                        if (nodeColl.Length > 0)
                        {
                            TreeNode n = nodeColl[0];
                            while (n != null && n != ProjectExplorer.TreeView.TopNode)
                            {
                                n.Expand();

                                n = n.Parent;
                            }

                            ProjectExplorer.TreeView.SelectedNode = nodeColl[0];
                        }
                    }

                    ProjectExplorer.TreeView.Refresh();
                    ProjectExplorer.TreeView.Focus();
                }
            }
            catch(Exception ex)
            {
                DialogError.ShowError(ex);
            }
        }

        public string StartupFolder
        {
            get;
            set;
        }

        public ProjectItem SelectedCodeFile
        {
            get;
            private set;
        }

        public ProjectItem SelectedItem
        {
            get
            {
                if (ProjectExplorer.TreeView.SelectedNode == null)
                    return null;

                ProjectItem item = ProjectExplorer.TreeView.SelectedNode.Tag as ProjectItem;

                return item;
            }
        }

        public CodeClass SelectedCodeClass
        {
            get
            {
                if (this.rdoClasses.Checked)
                {
                    return ucClassExplorer1.SelectedNode;
                }
                else
                {
                    if (ProjectExplorer.TreeView.SelectedNode == null)
                        return null;

                    ProjectItem item = ProjectExplorer.TreeView.SelectedNode.Tag as ProjectItem;
                    if (item == null || item.FileCodeModel == null)
                        return null;

                    CodeClass cls = null;
                    CodeElements elements = item.FileCodeModel.CodeElements;
                    foreach (CodeElement el in elements)
                    {
                        if (el is CodeNamespace)
                        {
                            foreach (CodeElement el2 in el.Children)
                            {
                                if (el2 is CodeClass)
                                {
                                    cls = el2 as CodeClass;
                                    break;
                                }
                            }

                            if (cls != null)
                                break;
                        }
                    }

                    return cls;

                }
            }
        }

        public bool FolderView
        {
            get;
            set;
        }

        public string SuggestedName
        {
            get;
            set;
        }

        private ProjectItems GetSelectedFolder(bool showErrors, bool onlyFoldersSelect)
        {
            if (ProjectExplorer.TreeView == null)
            {
                if (showErrors)
                    ShowErrorMessage();

                ProjectExplorer.TreeView.Focus();
                return null;
            }

            if (ProjectExplorer.TreeView.SelectedNode == null)
            {
                if (showErrors)
                    ShowErrorMessage();

                ProjectExplorer.TreeView.Focus();
                return null;
            }

            ProjectItem selected_item = ProjectExplorer.TreeView.SelectedNode.Tag as ProjectItem;
            ProjectItems items_collection = null;

            if (selected_item != null)
            {
                if (selected_item.Kind != Constants.vsProjectItemKindPhysicalFolder && onlyFoldersSelect)
                {
                    items_collection = null;
                }
                else 
                {
                    if (selected_item.Kind == Constants.vsProjectItemKindPhysicalFolder)
                    {
                        items_collection = selected_item.ProjectItems;
                    }
                    else
                    {
                        items_collection = selected_item.Collection;
                    }
                }
            }
            else if (ProjectExplorer.TreeView.SelectedNode.Tag is Project)
            {
                items_collection = (ProjectExplorer.TreeView.SelectedNode.Tag as Project).ProjectItems;
            }

            if (items_collection == null && showErrors)
            {
                ShowErrorMessage();
            }

            ProjectExplorer.TreeView.Focus();

            return items_collection;
        }

        private void ShowErrorMessage()
        {
            MessageBox.Show("You must select a folder where the file will be added under.", "Prompt", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
        }

        private void btnAddFromFile_Click(object sender, EventArgs e)
        {
            try
            {
                AddFileFromVSDialog(true);
            }
            catch (Exception ex)
            {
                DialogError.ShowError(ex);
            }

        }

        private void btnCreateFolder_Click(object sender, EventArgs e)
        {
            try
            {
                string safe_file_name;

                ProjectItems items_collection = GetSelectedFolder(true, true);
                if (items_collection == null)
                    return;

                using (DialogInputBox dialog = new DialogInputBox())
                {
                    dialog.Text = "Create folder";
                    dialog.InfoMessage = "Enter folder name";
                    DialogResult result = dialog.ShowDialog();

                    ProjectExplorer.TreeView.Focus();

                    if (result != DialogResult.OK)
                    {
                        return;
                    }

                    if (string.IsNullOrEmpty(dialog.InputText))
                        throw new Exception("Name can not be empty.");

                    safe_file_name = Common.FilterIllegalCharsInFileName(dialog.InputText);

                    items_collection.AddFolder(safe_file_name, Constants.vsProjectItemKindPhysicalFolder);
                    ProjectItem item = items_collection.Item(safe_file_name);

                    TreeNode node = ProjectExplorer.TreeView.SelectedNode.Nodes.Add(item.Name, item.Name);
                    node.ImageKey = "Folder";
                    node.SelectedImageKey = "Folder";
                    node.Tag = item;

                    ProjectExplorer.TreeView.Sort();

                    ProjectExplorer.TreeView.SelectedNode = node;
                    ProjectExplorer.TreeView.Focus();
                }

            }
            catch (Exception ex)
            {
                
                DialogError.ShowError(ex);
            }
        }

        private void btnDelete_Click(object sender, EventArgs e)
        {
            try
            {
                ProjectItems items_collection = GetSelectedFolder(true, false);
                if (items_collection == null)
                    return;

                ProjectItem item = items_collection.Parent as ProjectItem;
                if (item == null)
                {
                    MessageBox.Show("You can't delete the project node.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    return;
                }

                string msg = "Do you want to delete the item '" + Common.GetProjectItemPath(item, true) + "'?";
                if (MessageBox.Show(msg, "Prompt", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button2) != DialogResult.OK)
                    return;

                item.Delete();


                ProjectExplorer.TreeView.SelectedNode.Remove();
            }
            catch (Exception ex)
            {
                DialogError.ShowError(ex);
            }


        }

        private void btnAddItemEventRec_Click(object sender, EventArgs e)
        {
            try
            {
                AddFromPredefined(1);
            }
            catch (Exception ex)
            {
                DialogError.ShowError(ex);
            }
        }

        private void btnAddListEventRec_Click(object sender, EventArgs e)
        {
            try
            {
                AddFromPredefined(2);
            }
            catch (Exception ex)
            {
                DialogError.ShowError(ex);
            }
        }

        private void btnAddFeatureEventReceiver_Click(object sender, EventArgs e)
        {
            try
            {
                AddFromPredefined(3);
            }
            catch (Exception ex)
            {
                DialogError.ShowError(ex);
            }
        }

        private void AddFromPredefined(int EventType)
        {
            try
            {
                ProjectItems items_collection = GetSelectedFolder(true, true);
                if (items_collection == null)
                    return;


                string safe_file_name;

                using (DialogInputBox dialog = new DialogInputBox())
                {
                    dialog.Text = "Add new code file from predefined template";
                    dialog.InfoMessage = "Enter file name";

                    string ext;
                    if (items_collection.ContainingProject.CodeModel.Language == Common.C_CSPROJ_GUID)
                        ext = ".cs";
                    else if (items_collection.ContainingProject.CodeModel.Language == Common.C_VBPROJ_GUID)
                        ext = ".vb";
                    else
                        throw new NotImplementedException("Project language not supported.");

                    if (EventType == 3)
                    {
                        if (!string.IsNullOrEmpty(this.SuggestedName))
                        {
                            dialog.InputText = Common.FilterIllegalCharsInFileName(this.SuggestedName) + ext;
                        }
                        else
                        {
                            dialog.InputText = "FeatureEventReceiver" + ext;
                        }

                        dialog.InfoMessage = "Choose a file name for the feature event receiver. It will be created under '" + ProjectExplorer.TreeView.SelectedNode.Name + "'";
                        dialog.DialogTitle = "Enter file name";
                    }
                    else if (EventType == 2)
                    {
                        if (!string.IsNullOrEmpty(this.SuggestedName))
                        {
                            dialog.InputText = Common.FilterIllegalCharsInFileName(this.SuggestedName) + "_ListEventReceiver" + ext;
                        }
                        else
                        {
                            dialog.InputText = "ListEventReceiver" + ext;
                        }

                        dialog.InfoMessage = "Choose a file name for the list event receiver. It will be created under '" + ProjectExplorer.TreeView.SelectedNode.Name + "'";
                        dialog.DialogTitle = "Enter file name";
                    }
                    else
                    {
                        if (!string.IsNullOrEmpty(this.SuggestedName))
                        {
                            dialog.InputText = Common.FilterIllegalCharsInFileName(this.SuggestedName) + "_ListItemEventReceiver" + ext;
                        }
                        else
                        {
                            dialog.InputText = "ListItemEventReceiver" + ext;
                        }

                        dialog.InfoMessage = "Choose a file name for the list item event receiver. It will be created under '" + ProjectExplorer.TreeView.SelectedNode.Name + "'";
                        dialog.DialogTitle = "Enter file name";
                    }

                    DialogResult result = dialog.ShowDialog();

                    ProjectExplorer.TreeView.Focus();

                    if (result != DialogResult.OK)
                    {
                        return;
                    }

                    if (string.IsNullOrEmpty(dialog.InputText))
                        throw new Exception("Name can not be empty.");

                    safe_file_name = Common.FilterIllegalCharsInFileName(Path.GetFileNameWithoutExtension(dialog.InputText));
                    safe_file_name += Path.GetExtension(dialog.InputText);


                    string template_path;
                    if (EventType == 1)
                    {
                        template_path = Common.GetItemTemplatePath(items_collection.ContainingProject, "Item event receiver.zip", true);
                    }
                    else if (EventType == 2)
                    {
                        template_path = Common.GetItemTemplatePath(items_collection.ContainingProject, "List event receiver.zip", true);
                    }
                    else
                    {
                        template_path = Common.GetItemTemplatePath(items_collection.ContainingProject, "Feature event receiver.zip", true);
                    }
                    items_collection.AddFromTemplate(template_path, safe_file_name);

                    ProjectItem item = items_collection.Item(safe_file_name);

                    if (!string.IsNullOrEmpty(m_default_namespace))
                        SetNamespace(item, m_default_namespace);

                    item.Document.Close(vsSaveChanges.vsSaveChangesYes);

                    TreeNode node = ProjectExplorer.TreeView.SelectedNode.Nodes.Add(item.Name, item.Name);
                    node.ImageKey = "File";
                    node.SelectedImageKey = "File";
                    node.Tag = item;

                    ProjectExplorer.TreeView.Sort();

                    ProjectExplorer.TreeView.SelectedNode = node;
                    ProjectExplorer.TreeView.Focus();
                }
            }
            catch (Exception ex)
            {
                DialogError.ShowError(ex);
            }

        }

        private void SetNamespace(ProjectItem Item, string Namespace)
        {
            foreach (CodeElement element in Item.FileCodeModel.CodeElements)
            {
                if (element is CodeNamespace)
                {
                    (element as CodeNamespace).Name = Namespace;
                    break;
                }
            }
        }

        private void btnAddFromOtherTemplates_Click(object sender, EventArgs e)
        {
            try
            {
                AddFileFromVSDialog(false);
            }
            catch (Exception ex)
            {
                DialogError.ShowError(ex);
            }

        }

        private void AddFileFromVSDialog(bool bAddExisting)
        {
            ProjectItems items_collection = GetSelectedFolder(true, true);
            if (items_collection == null)
                return;

            ProjectItem selected_item = ProjectExplorer.TreeView.SelectedNode.Tag as ProjectItem;

            DTE2 dte2 = m_startup_project.DTE as DTE2;
            string parent = m_startup_project.UniqueName.Substring(0, m_startup_project.UniqueName.IndexOf("\\"));

            string path = string.Empty;
            if (selected_item != null)
                path = Common.GetProjectItemPath(selected_item, true);

            UIHierarchyItem ui_item = dte2.ToolWindows.SolutionExplorer.GetItem(parent + "\\" + m_startup_project.Name + "\\" + path);
            ui_item.Select(vsUISelectionType.vsUISelectionTypeSelect);

            if (bAddExisting)
            {
                dte2.ExecuteCommand("Project.AddExistingItem", "");
            }
            else
            {
                dte2.ExecuteCommand("Project.AddNewItem", "");
            }
            
            if (dte2.SelectedItems.Count == 0)
                return;

            ProjectItem new_item = dte2.SelectedItems.Item(1).ProjectItem as ProjectItem;
            if (new_item == null)
                return;

            if (!string.IsNullOrEmpty(m_default_namespace))
                SetNamespace(new_item, m_default_namespace);

            new_item.Document.Close(vsSaveChanges.vsSaveChangesYes);

            TreeNode node = ProjectExplorer.TreeView.SelectedNode.Nodes.Add(new_item.Name, new_item.Name);
            node.ImageKey = "File";
            node.SelectedImageKey = "File";
            node.Tag = new_item;

            ProjectExplorer.TreeView.Sort();

            ProjectExplorer.TreeView.SelectedNode = node;
            ProjectExplorer.TreeView.Focus();

        }

        private class ItemNodeComparer : IComparer
        {
            public int Compare(object x, object y)
            {
                ProjectItem itemX = (x as TreeNode).Tag as ProjectItem;
                ProjectItem itemY = (y as TreeNode).Tag as ProjectItem;

                if (itemX == null)
                    return -1;

                if (itemY == null)
                    return 1;

                if (itemX.Kind == Constants.vsProjectItemKindPhysicalFolder ||
                    itemX.Kind == Constants.vsProjectItemKindVirtualFolder)
                {
                    if (itemY.Kind == Constants.vsProjectItemKindPhysicalFolder ||
                        itemY.Kind == Constants.vsProjectItemKindVirtualFolder)
                        return string.Compare(itemX.Name, itemY.Name);
                    else
                        return -1;
                }
                else
                {
                    if (itemY.Kind != Constants.vsProjectItemKindPhysicalFolder &&
                        itemY.Kind != Constants.vsProjectItemKindVirtualFolder)
                        return string.Compare(itemX.Name, itemY.Name);
                    else
                        return 1;
                }
            }
        }
    }

}
